﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
using System.IO;

namespace HotelManager
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private Engine engine;
        private UIElement currentActiveRoomsElement;
        private UIElement currentGuests;
        private UIElement leavingGuests;
        private UIElement futureGuests;
        private Serializer serializer;

        public MainWindow()
        {
            InitializeComponent();

            serializer = new Serializer();

            engine = new Engine();

            if (File.Exists("engineData.txt"))
            {                
                InitializeEngine();
            }            

            engine.SaveData();

            currentActiveRoomsElement = this.OccupiedRoomsList;
            currentGuests = this.CurrentGuestsSheet;
            leavingGuests = this.LeavingGuestsSheet;
            futureGuests = this.FutureGuestsSheet;

            DisplayRooms();
            OnMenuOccupiedRoomsButtonClick(null, null);
        }
        
        private void InitializeEngine()
        {
            using (StreamReader engineDataReader = new StreamReader("engineData.txt"))
            {
                this.engine = this.serializer.HotelDataSerializer.Deserialize(engineDataReader, typeof(Engine)) as Engine;
            }
        }
        
        public void DisplayRooms()
        {
            this.RoomsPanel.Children.Clear();

            this.RoomsPanel.Children.Add(new TextBlock() { Width = 10000, Text = "Единични стаи", FontWeight = FontWeights.Black });

            foreach (Room room in engine.Rooms)
            {
                if (room is SingleRoom)
                {
                    ToggleButton button = InitializeButton(room);                    

                    this.RoomsPanel.Children.Add(button);
                }
            }
            
            this.RoomsPanel.Children.Add(new TextBlock() { Width = 10000, Text = "Двойни стаи", FontWeight = FontWeights.Black });

            foreach (Room room in engine.Rooms)
            {
                if (room is DoubleRoom)
                {
                    ToggleButton button = InitializeButton(room);

                    this.RoomsPanel.Children.Add(button);
                }
            }

            this.RoomsPanel.Children.Add(new TextBlock() { Width = 10000, Text = "Апартаменти", FontWeight = FontWeights.Black });

            foreach (Room room in engine.Rooms)
            {
                if (room is Apartment)
                {
                    ToggleButton button = InitializeButton(room);

                    this.RoomsPanel.Children.Add(button);
                }
            }
        }

        private ToggleButton InitializeButton(Room room)
        {
            ToggleButton button = new ToggleButton();
            button.Content = room.RoomNumber;
            button.Height = 35;
            button.Width = 50;
            button.Margin = new Thickness(0, 5, 10, 5);
            button.Background = Brushes.AliceBlue;

            if (room.IsOccupied)
            {
                button.Background = Brushes.PaleVioletRed;
            }

            if (room.IsReserved)
            {
                button.Background = Brushes.Green;
            }

            button.Checked += delegate (System.Object s, System.Windows.RoutedEventArgs e)
                {
                    var toggleButtons = this.RoomsPanel.Children.OfType<ToggleButton>();

                    foreach (ToggleButton b in toggleButtons)
                    {
                        b.IsChecked = false;
                    }

                    decimal price = 0;

                    switch (room.GetType().Name)
                    {
                        case "SingleRoom":
                            this.TextBoxRemoveRoomType.Text = "Единична стая";
                            price = engine.RoomsManager.SingleRoomPrice;
                            break;
                        case "DoubleRoom":
                            this.TextBoxRemoveRoomType.Text = "Двойна стая";
                            price = engine.RoomsManager.DoubleRoomPrice;
                            break;
                        case "Apartment":
                            this.TextBoxRemoveRoomType.Text = "Апартамент";
                            price = engine.RoomsManager.ApartmentPrice;
                            break;
                        default:
                            break;
                    }

                    string roomNumber = button.Content.ToString();

                    this.TextBoxCheckInRoomNumber.Text = roomNumber;
                    this.TextBoxReservationRoomNumber.Text = roomNumber;
                    this.TextBoxCheckInPrice.Text = price.ToString();
                    this.TextBoxReservationPrice.Text = price.ToString();
                    this.TextBoxCheckOutRoomNumber.Text = roomNumber;
                    this.TextBoxRemoveRoomNumber.Text = roomNumber;
                    this.TextBoxCancelReservationRoomNumber.Text = roomNumber;
                };

            return button;            
        }

        private void OnMenuOccupiedRoomsButtonClick(object sender, RoutedEventArgs e)
        {
            currentActiveRoomsElement.Visibility = Visibility.Collapsed;
            currentActiveRoomsElement = this.OccupiedRoomsList;
            
            var occupiedRoomsRentInfo =
                from r in engine.RentHistory
                where r.RentedItem.IsOccupied
                orderby r.RentedItem.RentDate descending
                select r;

            List<RentInfo> occupiedRoomsInfo = occupiedRoomsRentInfo.ToList();

            this.OccupiedRoomsGrid.ItemsSource = occupiedRoomsInfo;
            
            currentActiveRoomsElement.Visibility = Visibility.Visible;
        }

        private void OnMenuReservedRoomsButtonClick(object sender, RoutedEventArgs e)
        {
            currentActiveRoomsElement.Visibility = Visibility.Collapsed;
            currentActiveRoomsElement = this.ReservedRoomsList;

            var reservedRoomsInfo =
                from r in engine.ReservationHistory
                where r.TimeForCheckIn > DateTime.Now
                where !r.IsCanceled
                select r;

            this.ReservedRoomsGrid.ItemsSource = reservedRoomsInfo.ToList();

            currentActiveRoomsElement.Visibility = Visibility.Visible;
        }

        private void OnMenuCheckInButtonClick(object sender, RoutedEventArgs e)
        {            
            this.TextBoxCheckInRentFrom.Text = DateTime.Now.ToString();
            this.TextBoxCheckInAddress.Text = string.Empty;
            this.TextBoxCheckInDuration.Text = string.Empty;
            this.TextBoxCheckInEgn.Text = string.Empty;
            this.TextBoxCheckInFirstName.Text = string.Empty;
            this.TextBoxCheckInIdNumber.Text = string.Empty;
            this.TextBoxCheckInLastName.Text = string.Empty;
            this.TextBoxCheckInNationality.Text = string.Empty;
            this.TextBoxCheckInPhone.Text = string.Empty;

            currentActiveRoomsElement.Visibility = Visibility.Collapsed;
            currentActiveRoomsElement = this.CheckInForm;
            currentActiveRoomsElement.Visibility = Visibility.Visible;
        }

        private void OnMenuCheckOutButtonClick(object sender, RoutedEventArgs e)
        {
            this.TextBoxCheckOutMessage.Text = String.Empty;

            currentActiveRoomsElement.Visibility = Visibility.Collapsed;
            currentActiveRoomsElement = this.CheckOutForm;

            currentActiveRoomsElement.Visibility = Visibility.Visible;
        }

        private void OnMenuReservationButtonClick(object sender, RoutedEventArgs e)
        {
            this.TextBoxReservationRentFrom.Text = DateTime.Now.ToString();
            this.TextBoxReservationAddress.Text = string.Empty;
            this.TextBoxReservationDuration.Text = string.Empty;
            this.TextBoxReservationEgn.Text = string.Empty;
            this.TextBoxReservationFirstName.Text = string.Empty;
            this.TextBoxReservationIdNumber.Text = string.Empty;
            this.TextBoxReservationLastName.Text = string.Empty;
            this.TextBoxReservationNationality.Text = string.Empty;
            this.TextBoxReservationPhone.Text = string.Empty;

            currentActiveRoomsElement.Visibility = Visibility.Collapsed;
            currentActiveRoomsElement = this.ReservationForm;
            currentActiveRoomsElement.Visibility = Visibility.Visible;
        }

        private void OnMenuCancelReservationButtonClick(object sender, RoutedEventArgs e)
        {
            currentActiveRoomsElement.Visibility = Visibility.Collapsed;
            currentActiveRoomsElement = this.CancelReservationForm;
            currentActiveRoomsElement.Visibility = Visibility.Visible;
        }

        private void OnMenuAddRoomButtonClick(object sender, RoutedEventArgs e)
        {
            currentActiveRoomsElement.Visibility = Visibility.Collapsed;
            currentActiveRoomsElement = this.EditRoomForm;
            currentActiveRoomsElement.Visibility = Visibility.Visible;
        }
        
        private void OnAddRoomButtonClick(object sender, RoutedEventArgs e)
        {
            switch (this.AddRoomComboBox.Text)
            {
                case "Единична стая":
                    engine.Rooms.Add(new SingleRoom() { RoomNumber = int.Parse(this.TextBoxAddRoomNumber.Text) });
                    break;
                case "Двойна стая":
                    engine.Rooms.Add(new DoubleRoom() { RoomNumber = int.Parse(this.TextBoxAddRoomNumber.Text) });
                    break;
                case "Апартамент":
                    engine.Rooms.Add(new Apartment() { RoomNumber = int.Parse(this.TextBoxAddRoomNumber.Text) });
                    break;  
                default:
                    break;
            }

            engine.Rooms = engine.Rooms.OrderBy(r => r.RoomNumber).ToList();

            DisplayRooms();
            engine.SaveData();
        }

        private void OnRemoveRoomButtonClick(object sender, RoutedEventArgs e)
        {
            bool roomExists = engine.Rooms.Where<Room>(r => r.RoomNumber == int.Parse(this.TextBoxRemoveRoomNumber.Text)).Count<Room>() == 1;

            if (roomExists)
            {
                Room roomToRemove = engine.Rooms.Single<Room>(r => r.RoomNumber == int.Parse(this.TextBoxRemoveRoomNumber.Text));
                engine.Rooms.Remove(roomToRemove);
            }

            DisplayRooms();
            engine.SaveData();
        }

        private void OnChangeRoomPriceButtonClick(object sender, RoutedEventArgs e)
        {
            decimal price = decimal.Parse(this.TextBoxChangeRoomPrice.Text);

            switch (this.ChangeRoomPriceComboBox.Text)
            {
                case "Единична стая":
                    engine.RoomsManager.SingleRoomPrice = price;
                    break;
                case "Двойна стая":
                    engine.RoomsManager.DoubleRoomPrice = price;
                    break;
                case "Апартамент":
                    engine.RoomsManager.ApartmentPrice = price;
                    break;
                default:
                    break;
            }

            engine.SaveData();
        }

        private void OnMenuCurrentClientsButtonClick(object sender, RoutedEventArgs e)
        {
            currentGuests.Visibility = Visibility.Collapsed;
            futureGuests.Visibility = Visibility.Collapsed;
            leavingGuests.Visibility = Visibility.Collapsed;
            currentGuests = this.CurrentGuestsSheet;
            currentGuests.Visibility = Visibility.Visible;
        }

        private void OnLeavingClientsButtonClick(object sender, RoutedEventArgs e)
        {
            currentGuests.Visibility = Visibility.Collapsed;
            futureGuests.Visibility = Visibility.Collapsed;
            leavingGuests.Visibility = Visibility.Collapsed;
            leavingGuests = this.LeavingGuestsSheet;
            leavingGuests.Visibility = Visibility.Visible;
        }

        private void OnFutureClientsButtonClick(object sender, RoutedEventArgs e)
        {
            currentGuests.Visibility = Visibility.Collapsed;
            futureGuests.Visibility = Visibility.Collapsed;
            leavingGuests.Visibility = Visibility.Collapsed;
            futureGuests = this.FutureGuestsSheet;
            
            futureGuests.Visibility = Visibility.Visible;
        }

        private void OnCheckInButtonClick(object sender, RoutedEventArgs e)
        {
            Guest guest = new Guest(this.TextBoxCheckInFirstName.Text, this.TextBoxCheckInLastName.Text, 
                this.TextBoxCheckInAddress.Text, this.TextBoxCheckInPhone.Text, this.TextBoxCheckInEgn.Text, this.TextBoxCheckInIdNumber.Text, this.TextBoxCheckInNationality.Text);
                        
            Room room = engine.Rooms.Single<Room>(r => r.RoomNumber == int.Parse(this.TextBoxCheckInRoomNumber.Text));
            
            engine.CurrentAccount.CheckIn(guest, room, int.Parse(this.TextBoxCheckInDuration.Text), engine);

            DisplayRooms();
        }

        private void OnCheckOutButtonClick(object sender, RoutedEventArgs e)
        {
            Room roomToCheckOut = engine.Rooms.Single<Room>(r => r.RoomNumber == int.Parse(this.TextBoxCheckOutRoomNumber.Text));

            if (roomToCheckOut.IsOccupied)
            {
                Person guestToCheckOut = roomToCheckOut.CurrentGuest;

                engine.CurrentAccount.CheckOut(guestToCheckOut, roomToCheckOut, engine);

                this.TextBoxCheckOutMessage.Text = string.Format("Стая номер {0} освободена успешно.", roomToCheckOut.RoomNumber);

                DisplayRooms();
            }
            else
            {
                this.TextBoxCheckOutMessage.Text = string.Format("Стая номер {0} не е заета към момента.", roomToCheckOut.RoomNumber);
            }
        }

        private void OnReservationButtonClick(object sender, RoutedEventArgs e)
        {
            Guest guest = new Guest(this.TextBoxReservationFirstName.Text, this.TextBoxReservationLastName.Text,
                this.TextBoxReservationAddress.Text, this.TextBoxReservationPhone.Text, this.TextBoxReservationEgn.Text, this.TextBoxReservationIdNumber.Text, this.TextBoxReservationNationality.Text);

            Room room = engine.Rooms.Single<Room>(r => r.RoomNumber == int.Parse(this.TextBoxReservationRoomNumber.Text));

            engine.CurrentAccount.Reserve(guest, room, DateTime.Parse(this.TextBoxReservationRentFrom.Text), int.Parse(this.TextBoxReservationDuration.Text), engine);

            DisplayRooms();
        }

        private void OnCancelReservationButtonClick(object sender, RoutedEventArgs e)
        {
            Room roomToCancelReservation = engine.Rooms.Single<Room>(r => r.RoomNumber == int.Parse(this.TextBoxCancelReservationRoomNumber.Text));

            if (roomToCancelReservation.IsReserved)
            {
                Person guest = roomToCancelReservation.FutureGuest;

                engine.CurrentAccount.CancelReservation(guest, roomToCancelReservation, engine);

                this.TextBoxCancelReservationMessage.Text = string.Format("Стая номер {0} освободена успешно.", roomToCancelReservation.RoomNumber);

                DisplayRooms();
            }
            else
            {
                this.TextBoxCancelReservationMessage.Text = string.Format("Стая номер {0} не е резервирана към момента.", roomToCancelReservation.RoomNumber);
            }
        }
    }
}